﻿/*
 * measuremgr.cpp
 *
 *  Created on: 2017年3月27日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_SCADA DM_API_EXPORT

#include <dm/scada/measuremgr.hpp>

#include <dm/scada/scadainfo.hpp>
#include <dm/scada/devicemgr.hpp>
#include <dm/os/log/logger.hpp>
#include <dm/datetime.hpp>

namespace dm{
namespace scada{

static const char* logModule = "CMeasureMgr.scada.dm";

CMeasureMgr::CMeasureMgr( CScada& scada ):CScada(scada),
		m_cfg(scada.measureInfos(),scada.info()->measureCount()){
}

CMeasureMgr& CMeasureMgr::ins(){
	static CMeasureMgr i(CScada::ins());
	return i;
}

/**
 * 设置描述
 * @param idx
 * @param str
 * @return
 */
bool CMeasureMgr::setDesc( const index_t& idx,const char* str ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->desc = str;
		return true;
	}else
		return false;
}

/**
 * 设置基数
 * @param idx
 * @param base
 * @return
 */
bool CMeasureMgr::setBase( const index_t& idx,SMeasureInfo::base_t base ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->base = base;
		return true;
	}else
		return false;
}

/**
 * 设置系数
 * @param idx
 * @param coef
 * @return
 */
bool CMeasureMgr::setCoef( const index_t& idx,SMeasureInfo::coef_t coef ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->coef = coef;
		return true;
	}else
		return false;
}

/**
 * 设置变化限值
 * @param idx
 * @param delat
 * @return
 */
bool CMeasureMgr::setDelta( const index_t& idx,SMeasureInfo::delta_t delat ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->delta = delat;
		return true;
	}else
		return false;
}

/**
 * 设置单位
 * @param idx
 * @param unit
 * @return
 */
bool CMeasureMgr::setUnit( const index_t& idx,const char* unit ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->unit = unit;
		return true;
	}else
		return false;
}

/**
 * 设置存盘标志
 * @param idx
 * @param s
 * @return
 */
bool CMeasureMgr::setFlagSave( const index_t& idx,bool s ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagSave(s);
		return true;
	}else
		return false;
}

/**
 * 设置产生时标数据标志
 * @param idx
 * @param s
 * @return
 */
bool CMeasureMgr::setFlagGenTimed( const index_t& idx,bool s ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagGenTimed(s);
		return true;
	}else
		return false;
}

/**
 * 设置上报时标数据标志
 * @param idx
 * @param s
 * @return
 */
bool CMeasureMgr::setFlagReportTimed( const index_t& idx,bool s ){
	SMeasureInfo* p = m_cfg.at(idx);
	if( p ){
		p->setFlagReportTimed(s);
		return true;
	}else
		return false;
}

index_t CMeasureMgr::indexOfRt( const rt_t* value )const{
	if( value<measures() || value>measures()+size() )
		return Idx_Inv;
	return value - measures();
}

index_t CMeasureMgr::indexOfRt( const volatile rt_t* value )const{
	if( value<measures() || value>measures()+size() )
		return Idx_Inv;
	return value - measures();
}

index_t CMeasureMgr::deviceIndex( const index_t& idx )const{
	if( idx<0 || idx>=size() )
		return Idx_Inv;
	CDeviceMgr& d = CDeviceMgr::ins();

	for( index_t i=0;i<d.size();++i ){
		if( d.info(i)->posOfMeasure<=idx &&
				(d.info(i)->posOfMeasure+d.info(i)->sizeOfMeasure)>idx )
			return i;
	}

	return Idx_Inv;
}

const char* CMeasureMgr::deviceDesc( const index_t& idx )const{
	if( idx<0 || idx>=size() )
		return NULL;
	CDeviceMgr& d = CDeviceMgr::ins();

	for( index_t i=0;i<d.size();++i ){
		if( d.info(i)->posOfMeasure<=idx &&
				(d.info(i)->posOfMeasure+d.info(i)->sizeOfMeasure)>idx )
			return d.info(i)->desc.c_str();
	}

	return NULL;
}

inline bool deltaCheck( const float& f1,const float& f2,const float& delta ){
	if( delta==0 )
		return f1!=f2;
	else
		return (f1>f2)?((f1-f2)>=delta):((f2-f1)>=delta);
}

CMeasure::value_t CMeasureMgr::calcValue( const index_t& idx,const CMeasure::raw_t& raw )const{
	const SMeasureInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "测量量索引溢出%d>=%d",idx,size());
		return 0;
	}

	float v = raw-p->base;
	v *= p->coef;
	return v;
}

bool CMeasureMgr::update( const index_t& idx,const CMeasure::raw_t& raw,const EDataSource& ds,const dm::CTimeStamp& ts ){
	const SMeasureInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "测量量索引溢出%d>=%d",idx,size());
		return false;
	}

	float v = raw-p->base;
	v *= p->coef;

	if( deltaCheck(measures()[idx].getValue().getValue(),v,m_cfg.at(idx)->delta) ){
		measures()[idx].update(CMeasure(v,raw),ds,ts);

		if( p->isFlagGenTimed() ){
			CTimedMeasure tm(idx,v,ts);
			CTimedMeasureMgr::ins().push(tm);
		}

		return true;
	}else
		return false;

	return true;
}

bool CMeasureMgr::set( const index_t& idx,const CMeasure::raw_t& raw,const EDataSource& ds,const dm::CTimeStamp& ts ){
	const SMeasureInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "测量量索引溢出%d>=%d",idx,size());
		return false;
	}

	float v = raw-p->base;
	v *= p->coef;

	measures()[idx].update(CMeasure(v,raw),ds,ts);

	return true;
}

bool CMeasureMgr::gen( const index_t& idx,const CMeasure::raw_t& raw,const dm::CTimeStamp& ts ){
	const SMeasureInfo* p = info(idx);
	if( p==NULL ){
		log().warnning(THISMODULE "测量量索引溢出%d>=%d",idx,size());
		return false;
	}

	float v = raw-p->base;
	v *= p->coef;


	CTimedMeasure tm(idx,v,ts);
	CTimedMeasureMgr::ins().push(tm);

	return true;
}

void CMeasureMgr::printInfo( const index_t& idx,std::ostream& ostr )const{
	const SMeasureInfo* p = info(idx);
	if( p ){
		ostr	<<"Id:"<<p->id
				<<" 名字:"<<p->name.c_str()
				<<" 描述:"<<p->desc.c_str()
				<<" 最小变化值:"<<p->delta
				<<" 偏移:"<<p->base
				<<" 系数:"<<p->coef
				<<" 单位:"<<p->unit.c_str()
				<<" 存盘:";
		if( p->isFlagSave() )
			ostr <<"允许";
		else
			ostr <<"禁止";

		ostr <<" 产生时标数据:";
		if( p->isFlagGenTimed() )
			ostr <<"是";
		else
			ostr <<"否";

		ostr <<" 上报时标数据:";
		if( p->isFlagReportTimed() )
			ostr <<"是";
		else
			ostr <<"否";
	}else{
		ostr <<"无效索引("<<idx<<')';
	}
}

void CMeasureMgr::printInfoValue( const index_t& idx,std::ostream& ostr ){
	const SMeasureInfo* p = info(idx);
	if( p ){
		ostr	<<"Id:"<<p->id
				<<" 名字:"<<p->name.c_str()
				<<" 描述:"<<p->desc.c_str()
				<<" 值:"<<rtValue(idx)
				<<" 原始值:"<<rtRaw(idx)
				<<" 单位:"<<p->unit.c_str()
				<<" 时标:"<<dm::CDateTime(rtTs(idx)).toString().c_str();
	}else{
		ostr <<"无效索引("<<idx<<')';
	}
}
}
}
